#include <pthread.h>
#include <iostream>
#include <string>
#include <unistd.h>

using namespace std;

#define TNUM 4
volatile bool quit = false;

typedef void *(*func_t)(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *cond);

// 传递给新线程的参数(包含相关的数据)
class ThreadData
{
public:
    ThreadData(const string &name, func_t fun, pthread_mutex_t *pmtx, pthread_cond_t *cond)
        : _name(name), _func(fun), _pmtx(pmtx), _cond(cond) {}

    string _name;
    func_t _func;
    pthread_mutex_t *_pmtx;
    pthread_cond_t *_cond;
};

void *func1(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        // wait一定要在加锁和解锁之间wait
        // 一定要检测临界资源是否就绪(不就绪: 该线程进行等待, 直到被唤醒)
        pthread_cond_wait(pcond, pmtx); // wait代码被执行,当前线程会立即被阻塞
        cout << name << " running : 识别" << endl;
        pthread_mutex_unlock(pmtx);
    }
}

void *func2(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx);// wait代码被执行,当前线程会立即被阻塞
        cout << name << " running : 下载" << endl;
        pthread_mutex_unlock(pmtx);
    }
}

void *func3(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx);// wait代码被执行,当前线程会立即被阻塞
        cout << name << " running : 计算" << endl;
        pthread_mutex_unlock(pmtx);
    }
}

void *func4(const string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit)
    {
        pthread_mutex_lock(pmtx);
        // wait代码被执行,当前线程会立即被阻塞
        pthread_cond_wait(pcond, pmtx);
        cout << name << " running : 打印" << endl;
        pthread_mutex_unlock(pmtx);
    }
}

// 所有线程统一执行的方法
void *Entry(void *args)
{
    ThreadData *td = (ThreadData *)args;        // td在每一个线程私有的栈空间
    td->_func(td->_name, td->_pmtx, td->_cond); // 每个线程执行自己函数的方法
    delete td;                                  // 释放资源
}

int main()
{
    pthread_mutex_t mtx;
    pthread_cond_t cond;
    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);

    // 创建一批线程
    pthread_t tids[TNUM];
    func_t funcs[TNUM] = {func1, func2, func3, func4};

    for (int i = 0; i < TNUM; i++)
    {
        string name = "thread  ";
        name += to_string(i + 1);
        // 传的是锁的地址 --> 所有线程拿到的是同一把锁
        ThreadData *td = new ThreadData(name, funcs[i], &mtx, &cond);
        pthread_create(tids + i, nullptr, Entry, (void *)td);
    }

    sleep(3);

    int count = 10;
    // 主线程来控制唤醒
    while (count)
    {
        cout << "resume thread ..." << count--<< endl;
        // pthread_cond_broadcast(&cond);//唤醒所有线程
        pthread_cond_signal(&cond);
        sleep(1);
    }

    quit = true;
    pthread_cond_broadcast(&cond);//唤醒所有线程,让其在执行一次(检测) 线程执行完后,又可能继续去条件变量下等待

    // 等待线程
    for (int i = 0; i < TNUM; i++)
    {
        pthread_join(tids[i], nullptr);
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}
